Agents: Lab 2


In [1]:
from IPython.core.display import HTML
css_file = 'https://raw.githubusercontent.com/ngcm/training-public/master/ipython_notebook_styles/ngcmstyle.css'
HTML(url=css_file)


Out[1]:

Flocking behaviour

Agents should both interact with their environment and each other, and change their behaviour to reach some goal (often by maximizing a utility function or similar). One example is a simple model of the behaviour of groups of birds (flocking) or fish (schooling). This CSA model says that all individuals only change direction in order to improve

  • Cohesion: they steer towards the local average location of their flockmates;
  • Separation: they steer to avoid crowding local flockmates;
  • Alignment: they steer towards the average heading of their local flockmates.

Here we investigate how this model looks, depending on the initial velocity of the individuals.


In [2]:
%matplotlib inline
import math
import numpy
from matplotlib import pyplot, animation

from matplotlib import rcParams
rcParams['font.family'] = 'serif'
rcParams['font.size'] = 16
rcParams['figure.figsize'] = (12,6)

import scipy
from scipy.optimize import minimize

from __future__ import division

Define a class called Agent. This should store the 2-dimensional ${\bf z} = (x, y)$ location of the individual, and its 2-dimensional velocity ${\bf v} = (v_x, v_y)$. It should have a method that updates its location over a timestep $\Delta t$ as

\begin{equation} {\bf z} = \begin{pmatrix} x \\ y \end{pmatrix} \to \begin{pmatrix} x \\ y \end{pmatrix} + \Delta t \begin{pmatrix} v_x \\ v_y \end{pmatrix} = {\bf z} + \Delta t \, {\bf v}. \end{equation}

The Agent should also have a method that changes its velocity to maximize its "CSA utility": given a list of other agents that are the "local flockmates", it should choose its heading to maximize cohesion, separation and alignment. The CSA utility is a function of the locations and velocities that returns a single number, and is to be maximized by varying the direction of the velocity of this Agent.

As an example, define the following utility function:

\begin{equation} f \left( {\bf v} ; {\bf z}, {\bf z}_i, {\bf v}_i \right) = C \frac{{\bf v} \cdot \Delta {\bf z}}{ \| {\bf v} \| \| \Delta {\bf z} \| } + A \frac{{\bf v} \cdot {\bf V}}{ \| {\bf v} \| \| {\bf V} \| } - S \frac{{\bf v} \cdot \Delta {\bf z}_{\text{min}}}{ \| {\bf v} \| \| \Delta {\bf z}_{\text{min}} \|^3 }. \end{equation}

$f$ is the utility function itself. It depends on the velocity ${\bf v}$ of the current Agent, which can be varied. It also depends on the location ${\bf z}$ of the current Agent, as well as the locations ${\bf z}_i$ and velocities ${\bf v}_i$ of the local flockmates, which cannot be varied.

The coefficients $C, S, A$ give the relative importance of improving the cohesion, separation, and alignment respectively.

$\Delta {\bf z}$ is the average location difference between the current Agent position ${\bf z}$ and the position of its local flockmates ${\bf z}_i$, given by

\begin{equation} \Delta {\bf z} = \frac{1}{N} \sum_{i=1}^{N} \begin{pmatrix} x_i - x \\ y_i - y \end{pmatrix} \end{equation}

${\bf V}$ is the average velocity of the local flockmates, given by

\begin{equation} {\bf V} = \frac{1}{N} \sum_{i=1}^{N} \begin{pmatrix} (v_x)_i \\ (v_y)_i \end{pmatrix}. \end{equation}

$\Delta {\bf z}_{\text{min}}$ is the location of the flockmate that is closest to the current Agent. Note that the norm of this difference in the denominator is cubed, to ensure that when two agents get close together they are strongly repelled.

Note: it is only the direction of the velocity ${\bf v}$ that matters in this function. We can define a set of magnitudes and angles:

\begin{align} {\bf v} &= v \left( \cos(\theta) \hat{\bf i} + \sin(\theta) \hat{\bf j} \right), \\ \Delta {\bf z} &= \Delta z \left( \cos(\theta_z) \hat{\bf i} + \cos(\theta_z) \hat{\bf j} \right), \\ {\bf V} &= V \left( \cos(\theta_V) \hat{\bf i} + \cos(\theta_V) \hat{\bf j} \right), \\ \Delta {\bf z}_{\text{min}} &= \Delta z_{\text{min}} \left( \cos(\theta_{z_{\text{min}}}) \hat{\bf i} + \cos(\theta_{z_{\text{min}}}) \hat{\bf j} \right). \end{align}

We can then write

\begin{equation} f \left( \theta ; {\bf z}, {\bf z}_i, {\bf v}_i \right) = C \cos(\theta - \theta_z) + A \cos(\theta - \theta_V) - S \frac{\cos(\theta - \theta_{z_{\text{min}}})}{\Delta z_{\text{min}}^2 }. \end{equation}

To start, use values for the parameters of

\begin{align} C &= 1, \\ A &=5, \\ S &= 0.1. \end{align}

In [ ]:
class Agent(object):
    
    def __init__(self, location, velocity, C=1, A=5, S=0.1):
        # Complete this
    
    def step(self, dt): 
        # And this
        
    def steer(self, neighbours):
        # And this

Test that the Agent steers as expected given a list of zero or one local flockmates.


In [ ]:

Now define a Flock class containing a list of Agents. The flock should be initialized from appropriate numpy arrays and values for the locality radius $r_l$, which should default to 1. The flock should be able to compute and return

  • the positions of all its members
  • the average location of all its members
  • the average velocity, or heading, of all its members
  • the average distance from the average location.

Test, with flocks of one, two, and three agents, that it behaves as you expect. Timesteps of order $0.1$ for velocities of order $1$ are reasonable.


In [ ]:
class Flock(object):
    def __init__(self, locations, velocities, rl=1):
        # Complete this
    
    def step(self, dt):
        # And this
    
    def locations(self):
        # And this
    
    def velocities(self):
        # And this
    
    def average_location(self):
        # And this
    
    def average_velocity(self):
        # And this
    
    def average_width(self):
        # And this

In [ ]:

Create a flock of $50$ agents randomly distributed within $[0, 5]^2$. Give them initial velocities of $(1, 1) + 10^{-2} {\bf v}_r$, where ${\bf v}_r$ is a random velocity with each component a uniform random number in $[0, 1]$.

Evolve the flock using timesteps of $0.05$ for $200$ steps and plot the flock behaviour. Also plot the "width" of the flock (the average distance from the average location), and the average location and heading with time.


In [ ]: